package org.zhadoop.streaming.exception;

import java.text.MessageFormat;

/**
 * Streaming编译期所产生的异常的各种异常码
 * </p>
 * CQL异常码的设计
 * 异常码分为三个部分：
 * 前缀：以CQL-开头
 * 分类：两位数字编号，从00开头
 * 细分：三位数字编号，从000开头
 * </p>
 * 
 * 错误码 SQLSTATE异常描述
 * CQL-00 成功完成
 * CQL-01 警告
 * CQL-02 配置属性异常
 * CQL-03 流处理平台异常
 * CQL-04 语义分析异常，包含语法解析异常
 * CQL-05 拓扑异常，包含Streaming算子解析异常
 * CQL-06 函数解析异常
 * CQL-07 窗口解析异常
 * CQL-08 安全异常
 * CQL-99 未知异常
 * 
 * 不支持值得是后续可能支持
 * 不允许是以后再也不可能修改
 * 
 * @author zwd
 *
 */
public enum ErrorCode {
	//CQL-00成功完成
	/**
	 * 成功
	 */
	SUCCESS("00000","success."),
	
	//CQL-02 配置属性异常
	/**
	 * 找不到配置属性
	 */
	CONFIG_NOT_FOUND("02000","Cannot find config ''{0}''."),
	
	/**
	 * 配置属性数据类型转换失败
	 * 配置属性在CQL中设置的时候，都是String 类型
	 * 但是在具体使用的时候，需要的类型可能不一致，这就需要进行类型转换
	 * 该异常码就发生在配置属性在使用的时候，进行类型转换失败的场景
	 */
	CONFIG_FORMAT("02001", "Failed to convert config value ''{0}'' to type ''{1}''."),
	
	 /**
     * 应用程序的算子拓扑异常
     */
    PLATFORM_INVALID_TOPOLOGY("03003", "The submit topology is invalid."),
    
	/**
	 * 找不到对应流
	 */
	SEMANTICANALYZE_NOFOUND_STREAM("04008","Cannot find stream ''{0}''."),
	
	 /**
     * 常量类型转换失败
     */
    SEMANTICANALYZE_CONSTANT_FORMAT("04009", "Cannot format constant value ''{0}'' to ''{1}'' type."),
    
	/**
	 * 不支持的数据类型
	 */
	SEMANTICANALYZE_UNSUPPORTED_DATATYPE("04010","Unsupported data type ''{0}''."),
	 /**
     * 无法从所有的流中找到对应列
     */
    SEMANTICANALYZE_NO_COLUMN_ALLSTREAM("04012", "Cannot find column ''{0}'' in related streams."),
	/**
     * 无法唯一确定列, 该列可能存在在多个流中
     */
    SEMANTICANALYZE_DUPLICATE_COLUMN_ALLSTREAM("04013", "There is more than one column ''{0}'' in related streams."),
	/**
     * 无法根据名称找到对应流
     */
    SEMANTICANALYZE_NO_STREAM("04014", "Cannot find stream name ''{0}''."),
    
    /**
     * 算术表达式只支持number的数据类型
     */
    SEMANTICANALYZE_ARITHMETIC_EXPRESSION_NUMBER_TYPE("04023",
        "All expressions in arithmetic expression must be number type."),
    
	/**
	 * 流名称已经存在
	 */
	SEMANTICANALYZE_EXISTS_STREAM("04044","Stream name ''{0}'' already exists."),
	
	/**
	 * 表达式比较异常，一般是两个表达式类型不匹配，无法比较
	 * 比如String和Int类型比较
	 */
	SEMANTICANALYZE_EXPRESSION_DATATYPE_COMPARE("04045", "DataType ''{0}'' and ''{1}'' cannot compare."),
	/**
	 * 找不到序列化和反序列化
	 */
	SEMANTICANALYZE_UNKNOWN_SERDE("04041","Cannot find serialize/deserialize class."),
	  /**
     * 找不到类
     */
    SEMANTICANALYZE_UNKOWN_CLASS("04042", "Cannot find class ''{0}''."),
	/**
	 * 解析上下文为空
	 */
	SEMANTICANALYZE_CONTEXT_NULL("04047","ParseContext is null"),
	/**
	 * 算子不匹配
	 * 通常用于算子名称正确，但是被使用在了错误的地方
	 * 比如output位置使用了input算子
	 */
	 SEMANTICANALYZE_UNMATCH_OPERATOR("04057","The ''{0}'' operator type does not match."),
	/**
	 * 应用程序名称为空
	 */
	TOP_NO_NAME("05003","Application name is null"),
	/**
	 * 无法识别的时区
	 */
	TOP_ERROR_TIME_ZONE("05007","Unrecognized time zone ''{0}''."),
	
	/**
	 * 服务端异常
	 */
	UNKNOWN_SERVER_COMMON_ERROR("99000","An error occurred in CQL Engine"),
	/**
     * 未知异常
     */
    UNKNOWN_ERROR("99999", "Unknown error.");
	
	/**
	 * CQL 异常开头部分
	 */
	private static final String ERROR_HEAD = "ERROR";
	
	/**
	 * CQL异常前缀
	 */
	private static final String CODE_PREFIX = "CQL-";
	
	/**
	 * 前缀结束符号
	 */
	private static final String ERROR_PREFIX_END = ":";
	
	/**
	 * 异常码
	 */
	private String errorCode;
	
	/**
	 * SQL状态码
	 */
	private String sqlState;
	
	/**
	 * 异常消息，待格式化
	 */
	private String message;
	
	/**
	 * 格式化之后的消息
	 */
	private String formattedMessage;
	
	/**
	 * 消息格式化工具
	 */
	private MessageFormat formater;
	
	
	private ErrorCode(String code,String msg){
		this(code,msg,null);
	}
	
	private ErrorCode(String code,String msg,String state){
		this.errorCode = CODE_PREFIX + code;
		this.message = msg;
		this.sqlState = state;
		this.formater = new MessageFormat(message);
	}

	/**
	 * 获取全部异常的信息
	 * @param reasons
	 * @return
	 */
	public String getFullMessage(String... reasons){
		formatMessage(reasons);
		StringBuilder sb = new StringBuilder();
		sb.append(ERROR_HEAD);
		sb.append(errorCode);
		if(sqlState != null){
			sb.append(" (" + sqlState + ") ");
		}
		
		sb.append(ERROR_PREFIX_END);
		sb.append(formattedMessage);
		return sb.toString();
	}
	
	private void formatMessage(String... reasons) {
		this.formattedMessage = formater.format(reasons);
	}

	public String getErrorCode() {
		return errorCode;
	}

	public void setErrorCode(String errorCode) {
		this.errorCode = errorCode;
	}

	public String getSqlState() {
		return sqlState;
	}

	public void setSqlState(String sqlState) {
		this.sqlState = sqlState;
	}

	public String getFormattedMessage() {
		return formattedMessage;
	}

	public void setFormattedMessage(String formattedMessage) {
		this.formattedMessage = formattedMessage;
	}
	
	@Override
	public String toString() {
		return formattedMessage;
	}

}
